import sys
import typing

from PyQt5.QtCore import *
from PyQt5.QtGui import QDragEnterEvent, QDropEvent
from PyQt5.QtWidgets import QMainWindow, QHBoxLayout, QLabel, QApplication, QWidget, QVBoxLayout, QLineEdit, \
    QFormLayout, QCheckBox, QAction, QFileDialog, QMessageBox, QComboBox, QPushButton, QInputDialog

from gui.gl_widgets import UVGlWidget, VertexGlWidget, EditMode
from modules.moc3_accessor import MOC3Accessor
from modules.about import VERSION_STRING, NAME


MOC3_SUFFIX = ['.moc3']
TEXTURE_SUFFIX = ['.png']


class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        # notify
        print(self.tr("Check out the manual if you have no idea what is this for."))
        self.setWindowTitle('MOC3MeshEditor')

        self.setAcceptDrops(True)

        self._centralWidget = QWidget(self)
        # layout
        self.hLayout = QHBoxLayout(self._centralWidget)
        # ============= left, uv =============
        self.leftWidget = QWidget(self._centralWidget)
        self.leftVLayout = QVBoxLayout(self.leftWidget)
        self.uvGlWidget = UVGlWidget(self.leftWidget)   # gl uv
        self.leftVLayout.addWidget(self.uvGlWidget)
        self.leftVLayout.setStretch(0, 1)
        self.leftVLayout.setContentsMargins(0, 0, 0, 0)
        #    left toolbox start
        self.leftToolboxWidget = QWidget(self.leftWidget)
        self.leftToolboxHLayout = QHBoxLayout(self.leftToolboxWidget)
        self.leftToolboxHLayout.setContentsMargins(0, 0, 0, 0)
        self.leftToolLoadBgButton = QPushButton(self.leftToolboxWidget)
        self.leftToolLoadBgButton.setText(self.tr('load BG'))
        self.leftToolboxHLayout.addWidget(self.leftToolLoadBgButton)
        self.leftBackgroundSwitch = QCheckBox(self.leftToolboxWidget)
        self.leftBackgroundSwitch.setText('Show BG')
        self.leftToolboxHLayout.addWidget(self.leftBackgroundSwitch)
        self.leftToolComboHint = QLabel(self.leftToolboxWidget)
        self.leftToolComboHint.setText(self.tr('Edit mode:'))
        self.leftToolboxHLayout.addWidget(self.leftToolComboHint)
        self.leftToolCombo = QComboBox(self.leftToolboxWidget)
        self.leftToolCombo.addItem(self.tr('view'), 'view')
        self.leftToolCombo.addItem(self.tr('move'), 'move')
        self.leftToolboxHLayout.addWidget(self.leftToolCombo)
        self.leftRefreshIndexButton = QPushButton(self.leftToolboxWidget)
        self.leftRefreshIndexButton.setText(self.tr('re-index'))
        self.leftToolboxHLayout.addWidget(self.leftRefreshIndexButton)
        self.leftVLayout.addWidget(self.leftToolboxWidget)
        #    left toolbox end
        self.hLayout.addWidget(self.leftWidget)

        # ============= mid, editor =============
        self.midWidget = QWidget(self._centralWidget)
        self.midFLayout = QFormLayout(self.midWidget)
        self.midIdxLineEdit = QLineEdit(self.midWidget)
        self.midIdxLineEdit.setText("0")
        self.midIndexRangeHint = QLabel(self)
        self.midFLayout.addRow("", self.midIndexRangeHint)      # index
        self.midFLayout.addRow("index", self.midIdxLineEdit)
        self.midMeshNameHint = QLabel(self)
        self.midFLayout.addRow('name', self.midMeshNameHint)
        self.midFLayout.addRow("", QLabel("uv"))                # uv
        self.midHideNotFocusedCheckBox = QCheckBox(self.midWidget)
        self.midHideNotFocusedCheckBox.setText("focus only")
        self.midFLayout.addRow("config", self.midHideNotFocusedCheckBox)
        self.midUVIdxLineEdit = QLineEdit(self.midWidget)
        self.midUVIdxLineEdit.setText("0")
        self.midFLayout.addRow("idx", self.midUVIdxLineEdit)
        self.midUVXLineEdit = QLineEdit(self.midWidget)
        self.midFLayout.addRow("x", self.midUVXLineEdit)
        self.midUVYLineEdit = QLineEdit(self.midWidget)
        self.midFLayout.addRow("y", self.midUVYLineEdit)
        self.midFLayout.addRow("", QLabel("pos"))                       # pos
        self.midRollHintLabel = QLabel(self)
        self.midFLayout.addRow("roll cnt", self.midRollHintLabel)
        self.midPosIdxLineEdit = QLineEdit(self.midWidget)
        self.midFLayout.addRow("roll", self.midPosIdxLineEdit)
        self.midPosXLineEdit = QLineEdit(self.midWidget)
        self.midFLayout.addRow("x", self.midPosXLineEdit)
        self.midPosYLineEdit = QLineEdit(self.midWidget)
        self.midFLayout.addRow("y", self.midPosYLineEdit)
        # lock base
        # 三个互不相同的坐标，确认一个坐标系，锁定其基准点
        self.midLockBaseCheckBox1 = QCheckBox(self.midWidget)
        self.midLockBaseCheckBox1.setText("lock base")
        self.midFLayout.addRow("lock1", self.midLockBaseCheckBox1)
        self.midLockBaseCheckBox2 = QCheckBox(self.midWidget)
        self.midLockBaseCheckBox2.setText("lock base")
        self.midFLayout.addRow("lock2", self.midLockBaseCheckBox2)
        self.midLockBaseCheckBox3 = QCheckBox(self.midWidget)
        self.midLockBaseCheckBox3.setText("lock base")
        self.midFLayout.addRow("lock3", self.midLockBaseCheckBox3)
        # # hint text
        # self.midFLayout.addRow("", QLabel("hint"))
        # self.midHintTextBox = QPlainTextEdit(self.midWidget)
        # self.midHintTextBox.setReadOnly(True)
        # self.midFLayout.addRow("", self.midHintTextBox)
        # self.midFLayout.setContentsMargins(0, 0, 0, 0)
        # texture序号。默认-1表示展示所有贴图
        self.midFLayout.addRow("", QLabel("texture filter"))
        self.midTextureLineEdit = QLineEdit(self.midWidget)
        self.midTextureLineEdit.setText("-1")
        self.midFLayout.addRow("tx idx", self.midTextureLineEdit)

        self.hLayout.addWidget(self.midWidget)

        # ============= right, vertex =============
        self.rightWidget = QWidget(self._centralWidget)
        self.rightVLayout = QVBoxLayout(self.rightWidget)
        self.rightVLayout.setContentsMargins(0, 0, 0, 0)
        self.vertexGlWidget = VertexGlWidget(self.rightWidget)
        self.rightVLayout.addWidget(self.vertexGlWidget)
        self.rightVLayout.setStretch(0, 1)
        self.hLayout.addWidget(self.rightWidget)
        #   right toolbox start
        self.rightToolboxWidget = QWidget(self.rightWidget)
        self.rightToolboxHLayout = QHBoxLayout(self.rightToolboxWidget)
        self.rightToolboxHLayout.setContentsMargins(0, 0, 0, 0)
        self.rightShowBgCheckbox = QCheckBox(self.rightToolboxWidget)
        self.rightShowBgCheckbox.setText('Show BG')
        self.rightShowBgCheckbox.setChecked(True)
        self.rightToolboxHLayout.addWidget(self.rightShowBgCheckbox)
        _label = QLabel(self.rightToolboxWidget)
        _label.setText('Edit mode:')
        self.rightToolboxHLayout.addWidget(_label)
        self.rightEditModeCombo = QComboBox(self.rightToolboxWidget)
        self.rightEditModeCombo.addItem(self.tr('view'), 'view')
        self.rightEditModeCombo.addItem(self.tr('move'), 'move')
        self.rightToolboxHLayout.addWidget(self.rightEditModeCombo)
        self.rightVLayout.addWidget(self.rightToolboxWidget)
        #   right toolbox end

        # stretch
        self.hLayout.setStretch(0, 3)
        self.hLayout.setStretch(1, 2)
        self.hLayout.setStretch(2, 3)

        # ======== menu ========
        # file menu
        menubar = self.menuBar()
        fileMenu = menubar.addMenu(self.tr('File(&F)'))
        self.actOpen = QAction('Open(&O)', self)
        fileMenu.addAction(self.actOpen)
        self.actSave = QAction('Save(&S)', self)
        fileMenu.addAction(self.actSave)
        self.actSaveAs = QAction('Save as(&A)', self)
        fileMenu.addAction(self.actSaveAs)
        self.actClose = QAction('Close(&C)', self)
        fileMenu.addAction(self.actClose)

        # edit menu
        editMenu = menubar.addMenu(self.tr('Edit(&E)'))
        self.actSetTextureIdx = QAction('Set texture idx(&T)', self)
        editMenu.addAction(self.actSetTextureIdx)
        self.actCopyFromRoll = QAction('Copy from roll(&C)', self)
        editMenu.addAction(self.actCopyFromRoll)
        self.actCopyToRoll = QAction('Copy to roll(&R)', self)
        editMenu.addAction(self.actCopyToRoll)

        # help menu
        helpMenu = menubar.addMenu(self.tr('Help(&H)'))
        self.actAbout = QAction('About(&A)', self)
        helpMenu.addAction(self.actAbout)
        # menubar bind
        self._bind_menu()

        self.setCentralWidget(self._centralWidget)

        self.moc3_accessor: typing.Optional[MOC3Accessor] = None
        # binding
        self._bind_buttons()

        # test
        # self.open_moc3_file('./chuixue_3/chuixue_3.moc3')

    def open_moc3_file(self, file: str):
        self.moc3_accessor = MOC3Accessor(file)
        self.vertexGlWidget.set_canvas_rect(self.moc3_accessor.get_canvas_size(), self.moc3_accessor.get_canvas_origin())
        self._setup_gl()
        # 在窗口标题显示文件名
        self.setWindowTitle(f"MOC3MeshEditor - {self.moc3_accessor.get_file_name()}")

    def _bind_menu(self):
        # signal
        def _on_menu_open():
            _file, _type = QFileDialog.getOpenFileName(self, self.tr('open moc3 file'))
            if len(_file) == 0:
                return
            self.open_moc3_file(_file)
        self.actOpen.triggered.connect(_on_menu_open)

        def _on_menu_save():
            if self.moc3_accessor is None:
                QMessageBox.warning(self, self.tr('Save file'), self.tr('Cannot save because no file was open.'))
                return
            r = QMessageBox.question(self, self.tr('Save file'), self.tr('Are you sure to overwrite the opening file?'))
            if r == QMessageBox.StandardButton.Yes:
                self.moc3_accessor.save()
        self.actSave.triggered.connect(_on_menu_save)

        def _on_menu_save_as():
            if self.moc3_accessor is None:
                QMessageBox.warning(self, self.tr('Save file'), self.tr('Cannot save because no file was open.'))
                return
            _file, _type = QFileDialog.getSaveFileName(self, self.tr('Save as'))
            if len(_file) == 0:
                return
            self.moc3_accessor.save_as(_file)
        self.actSaveAs.triggered.connect(_on_menu_save_as)

        def _on_menu_about():
            QMessageBox.about(self, self.tr('About'), f'{NAME} {VERSION_STRING}')
        self.actAbout.triggered.connect(_on_menu_about)

        def _on_set_texture_idx():
            if self.moc3_accessor is None:
                QMessageBox.warning(self, self.tr('Set texture idx'), self.tr('Cannot set texture idx because no file was open.'))
                return
            # 从对话框中获取新的贴图序号
            _idx, _ok = QInputDialog.getInt(self, self.tr('Set texture idx'), self.tr('Enter texture index:'), value=0, min=0, max=1000000)
            if _ok:
                self.moc3_accessor.set_current_texture_idx(_idx)
        self.actSetTextureIdx.triggered.connect(_on_set_texture_idx)

        def _on_copy_from_roll():
            if self.moc3_accessor is None:
                QMessageBox.warning(self, self.tr('Copy from roll'), self.tr('Cannot copy from roll because no file was open.'))
                return
            max_roll = self.moc3_accessor.get_current_roll_max()
            if max_roll == 0:
                QMessageBox.warning(self, self.tr('Copy from roll'), self.tr('Cannot copy from roll because no roll was found.'))
                return
            _roll, _ok = QInputDialog.getInt(self, self.tr('Copy from roll'), self.tr('Enter roll index:'), value=0, min=0, max=max_roll-1)
            if not _ok:
                return
            self.moc3_accessor.copy_roll(_roll, self.moc3_accessor.get_current_roll())
        self.actCopyFromRoll.triggered.connect(_on_copy_from_roll)

        def _on_copy_to_roll():
            if self.moc3_accessor is None:
                QMessageBox.warning(self, self.tr('Copy to roll'), self.tr('Cannot copy to roll because no file was open.'))
                return
            max_roll = self.moc3_accessor.get_current_roll_max()
            if max_roll == 0:
                QMessageBox.warning(self, self.tr('Copy from roll'), self.tr('Cannot copy from roll because no roll was found.'))
                return
            _roll, _ok = QInputDialog.getInt(self, self.tr('Copy to roll'), self.tr('Enter roll index:'), value=0, min=0, max=max_roll-1)
            if not _ok:
                return
            self.moc3_accessor.copy_roll(self.moc3_accessor.get_current_roll(), _roll)
        self.actCopyToRoll.triggered.connect(_on_copy_to_roll)

    def _bind_buttons(self):
        def _on_idx_changed(content: str):
            try:
                v = int(content)
                self.vertexGlWidget.set_highlight_idx(v)
                self.uvGlWidget.set_highlight_idx(v)
                if self.moc3_accessor is not None:
                    self.moc3_accessor.moveto_idx(v)
                    self.update_uv_pos_by_accessor()
                    self.midUVIdxLineEdit.setText('0')
                    _rc = self.moc3_accessor.get_current_roll_max()
                    self.midRollHintLabel.setText(str(_rc))
                    self.midPosIdxLineEdit.setText('0')
                    self.midPosIdxLineEdit.setEnabled(_rc > 1)
                    self.midMeshNameHint.setText(self.moc3_accessor.get_current_mesh_name())
            except Exception as e:
                print(e)
        self.midIdxLineEdit.textEdited.connect(_on_idx_changed)

        def _on_vertex_idx_edited(content: str):
            try:
                v = int(content)
                self.vertexGlWidget.set_highlight_vertex(v)
                self.uvGlWidget.set_highlight_vertex(v)
                if self.moc3_accessor is not None:
                    self.moc3_accessor.moveto_vertex(v)
                    self.update_uv_pos_by_accessor()
            except Exception as e:
                print(e)
        self.midUVIdxLineEdit.textEdited.connect(_on_vertex_idx_edited)

        def _on_uv_focus(idx: int, vx: int):
            self.midIdxLineEdit.setText(str(idx))
            _on_idx_changed(str(idx))
            self.midUVIdxLineEdit.setText(str(vx))
            _on_vertex_idx_edited(str(vx))
        self.uvGlWidget.onFocus.connect(_on_uv_focus)

        def _on_hide_not_focused_changed(value: int):
            self.uvGlWidget.set_focus_only(value == 2)
        self.midHideNotFocusedCheckBox.stateChanged.connect(_on_hide_not_focused_changed)

        def _on_roll_edited(content: str):
            try:
                v = int(content)
                self.vertexGlWidget.set_roll_idx(v)
                if self.moc3_accessor is not None:
                    self.moc3_accessor.moveto_roll(v)
                    self.update_uv_pos_by_accessor()
            except Exception as e:
                print(e)
        self.midPosIdxLineEdit.textEdited.connect(_on_roll_edited)

        # UV数值编辑，反向写入
        def _on_uv_data_edited(_: str):
            try:
                _x = float(self.midUVXLineEdit.text())
                _y = float(self.midUVYLineEdit.text())
                self.moc3_accessor.set_current_uv(_x, _y)
                self.uvGlWidget.force_resize()
            except Exception as e:
                print(e)
        self.midUVXLineEdit.textEdited.connect(_on_uv_data_edited)
        self.midUVYLineEdit.textEdited.connect(_on_uv_data_edited)

        def _on_pos_data_edited(_: str):
            try:
                _x = float(self.midPosXLineEdit.text())
                _y = float(self.midPosYLineEdit.text())
                self.moc3_accessor.set_current_pos(_x, _y)
                self.vertexGlWidget.force_resize()
            except Exception as e:
                print(e)
        self.midPosXLineEdit.textEdited.connect(_on_pos_data_edited)
        self.midPosYLineEdit.textEdited.connect(_on_pos_data_edited)

        def _on_button_load_bg():
            _file, _type = QFileDialog.getOpenFileName(self, self.tr('open texture file'), filter=self.tr("Images (*.png *.xpm *.jpg)"))
            if len(_file) == 0:
                return
            self.uvGlWidget.load_texture(_file)
        self.leftToolLoadBgButton.clicked.connect(_on_button_load_bg)

        def _on_show_bg_changed(stat: int):
            if stat == Qt.CheckState.Checked:
                self.uvGlWidget.set_show_bg(True)
            elif stat == Qt.CheckState.Unchecked:
                self.uvGlWidget.set_show_bg(False)
        self.leftBackgroundSwitch.stateChanged.connect(_on_show_bg_changed)

        def _on_right_show_bg_changed(stat: int):
            if stat == Qt.CheckState.Checked:
                self.vertexGlWidget.set_show_bg(True)
            elif stat == Qt.CheckState.Unchecked:
                self.vertexGlWidget.set_show_bg(False)
        self.rightShowBgCheckbox.stateChanged.connect(_on_right_show_bg_changed)

        def _on_left_edit_mode_edited(idx: int):
            if idx == 0:
                self.uvGlWidget.set_edit_mode(EditMode.VIEW)
            elif idx == 1:
                self.uvGlWidget.set_edit_mode(EditMode.MOVE)
        self.leftToolCombo.currentIndexChanged.connect(_on_left_edit_mode_edited)

        def _on_right_edit_mode_edited(idx: int):
            if idx == 0:
                self.vertexGlWidget.set_edit_mode(EditMode.VIEW)
            elif idx == 1:
                self.vertexGlWidget.set_edit_mode(EditMode.MOVE)
        self.rightEditModeCombo.currentIndexChanged.connect(_on_right_edit_mode_edited)

        def _on_left_edit_move(dx: float, dy: float):
            if self.moc3_accessor is None:
                return
            _x, _y = self.moc3_accessor.get_current_uv()
            if self.uvGlWidget.get_edit_mode() == EditMode.VIEW:
                self.moc3_accessor.set_current_uv(_x + dx, _y + dy)
                if self.is_all_base_locked():
                    self.moc3_accessor.update_corresponding_pos()
                    self.vertexGlWidget.force_resize()
                    _pos = self.moc3_accessor.get_current_pos()
                    self.midPosXLineEdit.setText(str(_pos[0]))
                    self.midPosYLineEdit.setText(str(_pos[1]))
            elif self.uvGlWidget.get_edit_mode() == EditMode.MOVE:
                self.moc3_accessor.move_current_uv_art_mesh(dx, dy)
            self.midUVXLineEdit.setText(str(_x + dx))
            self.midUVYLineEdit.setText(str(_y + dy))
        self.uvGlWidget.onMoveCurrent.connect(_on_left_edit_move)

        def _on_right_edit_move(dx: float, dy: float):
            if self.moc3_accessor is None:
                return
            _x, _y = self.moc3_accessor.get_current_pos()
            if self.vertexGlWidget.get_edit_mode() == EditMode.VIEW:
                self.moc3_accessor.set_current_pos(_x + dx, _y + dy)
                if self.is_all_base_locked():
                    self.moc3_accessor.update_corresponding_uv()
                    self.uvGlWidget.force_resize()
                    _uv = self.moc3_accessor.get_current_uv()
                    self.midUVXLineEdit.setText(str(_uv[0]))
                    self.midUVYLineEdit.setText(str(_uv[1]))
            elif self.vertexGlWidget.get_edit_mode() == EditMode.MOVE:
                self.moc3_accessor.move_current_pos_art_mesh(dx, dy)
            self.moc3_accessor.set_current_pos(_x + dx, _y + dy)
            self.midPosXLineEdit.setText(str(_x + dx))
            self.midPosYLineEdit.setText(str(_y + dy))
        self.vertexGlWidget.onMoveCurrent.connect(_on_right_edit_move)

        def _on_button_refresh_index_left():
            self.uvGlWidget.refresh_indexes()
        self.leftRefreshIndexButton.clicked.connect(_on_button_refresh_index_left)

        def _on_texture_loaded(width: int, height: int):
            self.moc3_accessor.set_uv_size(width, height)
            self.uvGlWidget.set_canvas_size(width, height)
        self.uvGlWidget.textureLoaded.connect(_on_texture_loaded)

        def _on_lock_base_changed(idx: int, value: int):
            if self.moc3_accessor is None:
                return
            if value == Qt.CheckState.Checked:
                vi = self.moc3_accessor.get_current_vertex()
                self.uvGlWidget.set_lock_base(idx, vi)
                self.vertexGlWidget.set_lock_base(idx, vi)
                self.moc3_accessor.set_lock_base(idx, vi)
            elif value == Qt.CheckState.Unchecked:
                self.uvGlWidget.set_lock_base(idx, -1)
                self.vertexGlWidget.set_lock_base(idx, -1)
                self.moc3_accessor.set_lock_base(idx, -1)
        self.midLockBaseCheckBox1.stateChanged.connect(lambda _v: _on_lock_base_changed(0, _v))
        self.midLockBaseCheckBox2.stateChanged.connect(lambda _v: _on_lock_base_changed(1, _v))
        self.midLockBaseCheckBox3.stateChanged.connect(lambda _v: _on_lock_base_changed(2, _v))

        def _on_right_wheel_vertex(delta: int):
            if self.moc3_accessor is None:
                return
            t_idx = self.midUVIdxLineEdit.text()
            if not t_idx.isdigit():
                t_idx = '0'
            t_idx = int(t_idx)
            if delta > 0:
                content = str(t_idx - 1)
            elif delta < 0:
                content = str(t_idx + 1)
            else:
                content = str(t_idx)
            _on_vertex_idx_edited(content)
            self.midUVIdxLineEdit.setText(str(self.moc3_accessor.get_current_vertex()))
        self.vertexGlWidget.onWheelSetVertex.connect(_on_right_wheel_vertex)

        def _on_texture_idx_edited(content: str):
            try:
                v = int(content)
                self.uvGlWidget.set_texture_idx(v)
            except Exception as e:
                print(e)
        self.midTextureLineEdit.textEdited.connect(_on_texture_idx_edited)


    def is_all_base_locked(self) -> bool:
        return self.midLockBaseCheckBox1.isChecked() and self.midLockBaseCheckBox2.isChecked() and self.midLockBaseCheckBox3.isChecked()

    def update_uv_pos_by_accessor(self):
        _x, _y = self.moc3_accessor.get_current_uv()
        self.midUVXLineEdit.setText(str(_x))
        self.midUVYLineEdit.setText(str(_y))
        _x, _y = self.moc3_accessor.get_current_pos()
        self.midPosXLineEdit.setText(str(_x))
        self.midPosYLineEdit.setText(str(_y))

    def _setup_gl(self):
        self.uvGlWidget.moc3_vertex_cnt = self.moc3_accessor.access_moc3_data('_moc3_vertex_cnt')
        self.uvGlWidget.moc3_uv_idx = self.moc3_accessor.access_moc3_data('_moc3_uv_idx')
        self.uvGlWidget.moc3_uv_xy = self.moc3_accessor.access_moc3_data('_moc3_uv_xy')
        self.uvGlWidget.moc3_drawable_start = self.moc3_accessor.access_moc3_data('_moc3_drawable_start')
        self.uvGlWidget.moc3_drawable_cnt = self.moc3_accessor.access_moc3_data('_moc3_drawable_cnt')
        self.uvGlWidget.moc3_drawable_index = self.moc3_accessor.access_moc3_data('_moc3_drawable_index')
        self.uvGlWidget.moc3_mesh_texture = self.moc3_accessor.access_moc3_data('_moc3_mesh_texture')
        self.uvGlWidget.refresh_indexes()

        self.vertexGlWidget.moc3_vertex_cnt = self.moc3_accessor.access_moc3_data('_moc3_vertex_cnt')
        self.vertexGlWidget.moc3_uv_idx = self.moc3_accessor.access_moc3_data('_moc3_uv_idx')
        self.vertexGlWidget.moc3_uv_xy = self.moc3_accessor.access_moc3_data('_moc3_uv_xy')
        self.vertexGlWidget.moc3_drawable_start = self.moc3_accessor.access_moc3_data('_moc3_drawable_start')
        self.vertexGlWidget.moc3_drawable_cnt = self.moc3_accessor.access_moc3_data('_moc3_drawable_cnt')
        self.vertexGlWidget.moc3_drawable_index = self.moc3_accessor.access_moc3_data('_moc3_drawable_index')
        self.vertexGlWidget.moc3_kf_idx = self.moc3_accessor.access_moc3_data('_moc3_kf_idx')
        self.vertexGlWidget.moc3_kf_cnt = self.moc3_accessor.access_moc3_data('_moc3_kf_cnt')
        self.vertexGlWidget.moc3_kf_idx2pos = self.moc3_accessor.access_moc3_data('_moc3_kf_idx2pos')
        self.vertexGlWidget.moc3_kf_data = self.moc3_accessor.access_moc3_data('_moc3_kf_data')

    def dragEnterEvent(self, e: QDragEnterEvent):
        # 仅接受单个url
        if e.mimeData().hasUrls() and len(e.mimeData().urls()) == 1:
            e.accept()

    def dropEvent(self, e: QDropEvent):
        # 根据文件后缀判断类型，并打开文件
        url = e.mimeData().urls()[0]
        file = url.toLocalFile()
        if any(file.endswith(ext) for ext in MOC3_SUFFIX):
            self.open_moc3_file(file)
        elif any(file.endswith(ext) for ext in TEXTURE_SUFFIX):
            self.uvGlWidget.load_texture(file)
        else:
            print('warning: unknown file type: ' + file)


def start_main_window():
    app = QApplication(sys.argv)
    window = MainWindow()
    window.resize(960, 600)
    window.show()
    sys.exit(app.exec_())
